/******************************************
 * Métodos Numéricos - TP1 "Mandelzoom"
 *
 * main.cpp
 * Punto de entrada del programa que lee los argumentos de usuario
 *
 ******************************************/
 
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdio>
#include <cstdlib>

#include "mandelzoom.h"

using namespace std;

/**
 * Muestra la forma de uso del programa cuando es llamado con parámetros inválidos.
 * Luego hace una pausa y finaliza el programa.
 *
 * NOTA: considérese documentación de la función main de este archivo.
 */
void mostrarUso() {
    cerr << endl;
    cerr << "Uso:"                                                                             << endl;
    cerr << " o './mandel big $nombre $x1 $x2 $y1 $y2 $xScale $yScale $maxIter $precision'"    << endl;
    cerr << "            las coordenadas y la escala son interpretados como BigFloat's "       << endl;
    cerr                                                                                       << endl;
    cerr << " o './mandel dbl $nombre $x1 $x2 $y1 $y2 $res $maxIter $precision'"               << endl;
    cerr << "            las coordenadas son interpretadas como double's y $res es un "        << endl;
    cerr << "            int que especifica el maximo entre el alto y el ancho en "            << endl;
    cerr << "            pixeles del bmp de salida;"                                           << endl;
    cerr                                                                                       << endl;

    system("PAUSE");
    exit(1);
}

/**
 * Calcula a partir de los parámetros la resolución (cantidad de pixeles que se
 * dibujarán) del bmp que generaría la función mandel. El cálculo es
 *
 *          (xRes, yRes) = ((x2 - x1) / xScale, (y2 - y2) / yScale)
 *
 * Dado que no es requerido que el tipo 'BigFloat' implemente la división, los valores se
 * convertirán a double's antes de ser divididos, por lo tanto el resultado puede no ser
 * exacto. Luego se informará al usuario la resolución calculada.
 * Si la resolución es válida el usuario podrá continuar para que efectivamente se genere
 * el bmp. En caso contrario deberá llamar nuevamente al programa con nuevos parámetros.
 */
int escalaBigFloat(const char* path,
         BigFloat x1, BigFloat x2, BigFloat y1, BigFloat y2,
         BigFloat xScale, BigFloat yScale,
         bool generar, int maxIteraciones, int precision);

/**
 * Llama a la función mandel convirtiendo coordenadas de tipo double a BigFloat.
 */
int escalaDouble(const char* name,
         double x1, double x2, double y1, double y2,
         int resolucion,
         bool generar, int maxIteraciones, int precision);

int main(int argc, char** argv) {

    if(argc < 2) mostrarUso();

    string modo = argv[1];
    if(modo == "big") {
        if(argc != 11) {
            cerr << "Cantidad erronea de parametros para modo big" << endl;
            return 1;
        }
        int maxIter = atoi(argv[9]);
        int precis = atoi(argv[10]);
        
        return escalaBigFloat(argv[2],
            BigFloat(precis, argv[3]),
            BigFloat(precis, argv[4]),
            BigFloat(precis, argv[5]),
            BigFloat(precis, argv[6]),
            BigFloat(precis, argv[7]),
            BigFloat(precis, argv[8]),
            maxIter > 0,
            maxIter,
            precis
        );
    } else if(modo == "dbl") {
        if(argc != 10) {
            cerr << "Cantidad erronea de parametros para modo dbl" << endl;
            return 1;
        }
        int resolucion = atoi(argv[7]);
        
        int maxIter = atoi(argv[8]);
        int precis = atoi(argv[9]);
        
        return escalaDouble(argv[2],
            strtold(argv[3], 0),
            strtold(argv[4], 0),
            strtold(argv[5], 0),
            strtold(argv[6], 0),
            resolucion,
            maxIter > 0,
            maxIter,
            precis
        );
    } else {
        mostrarUso();
        return 1;
    }

}

int escalaBigFloat(const char* name,
         BigFloat x1, BigFloat x2, BigFloat y1, BigFloat y2,
         BigFloat xScale, BigFloat yScale, bool generar, int maxIteraciones, int precis) {

    BigFloat dx = x2; dx.restar(x1);
    BigFloat dy = y2; dy.restar(y1);

    int xRes, yRes;
    xRes = BigFloat::razon(dx, xScale);
    yRes = BigFloat::razon(dy, yScale);

    cerr << "Resolucion:  " << xRes << "x" << yRes << endl;
    if(xRes < 1 || yRes < 1 || xRes > 10000 || yRes > 10000) {
        cerr << "Resolucion invalida" << endl;
        return 1;
    }

    if(!generar) return 0;

    string bmpPath = name;
    bmpPath += ".bmp";
    
    Mandel m;
    return m.generar(bmpPath.data(), x1, y1, xScale, yScale, xRes, yRes, maxIteraciones, precis);
}

int escalaDouble(const char* name,
         double x1, double x2, double y1, double y2,
         int resolucion, bool generar, int maxIteraciones, int precis) {

    if(!generar) return 0;

    double dx = x2 - x1;
    double dy = y2 - y1;

    double escalaDbl = max(dx, dy) / resolucion;

    int xRes = dx / escalaDbl;
    int yRes = dy / escalaDbl;

    cerr << "Resolucion:  " << xRes << "x" << yRes << endl;
    if(xRes < 1 || yRes < 1 || xRes > 10000 || yRes > 10000) {
        cerr << "Resolucion invalida" << endl;
        return 1;
    }

    cerr << "Escala:      " << escalaDbl << endl;
    BigFloat escala = BigFloat(precis, escalaDbl);

    string bmpPath = name;
    bmpPath += ".bmp";
    
    Mandel m;
    return m.generar(bmpPath.data(),
        BigFloat(precis, x1),
        BigFloat(precis, y1),
        escala, escala,
        xRes, yRes,
        maxIteraciones,
        precis
    );
}
